﻿namespace BlazorAdmin.Tcp.Protocol
{
    /// <summary>
    /// 设备通讯协议基类
    /// </summary>
    public class DeviceProtocol : ProtocolBase
    {
        public DeviceProtocol()
        {
            Header = HeaderFrame;
            mappings = DataCode.GetMappings();
        }

        private static readonly byte[] HeaderFrame = new byte[] { 0x4C, 0x45, 0x4E, 0x53 };

        private readonly Dictionary<TcpPolicy, DataTypeAttribute> mappings;

        /// <summary>
        /// 业务主类型
        /// </summary>
        public virtual FrameMode FrameMode { get; protected set; } = FrameMode.HeartBeat;

        /// <summary>
        /// 指令所属类型
        /// </summary>
        public Dictionary<TcpPolicy, object>? DataCache { get; set; }

        /// <summary>
        /// 连接端应用程序版本号
        /// </summary>
        public virtual string? Version { get; set; }

        /// <summary>
        /// 客户端TCP请求的数据
        /// </summary>
        public virtual string? RequestData { get; set; }

        /// <summary>
        /// 将数据帧中的数据域解析成对应的协议对象
        /// </summary>
        /// <param name="dataFrame">数据帧中的数据域</param>
        /// <returns></returns>
        public virtual void AnalysisData(byte[] dataFrame, int start, int count)
        {
            if (count < 2)
                return;
            int idx = start;
            int total = count;
            DataCache = new Dictionary<TcpPolicy, object>();
            do
            {
                TcpPolicy dataCode = (TcpPolicy)dataFrame[idx++];
                if (dataCode == TcpPolicy.NONE || !mappings.TryGetValue(dataCode, out DataTypeAttribute? convert) || null == convert)
                    break;
                object? value;
                int len;
                switch (dataCode)
                {
                    case TcpPolicy.GUID:
                    case TcpPolicy.Registration:
                        (value, len) = convert.GetString(dataFrame, idx);
                        break;
                    default: return;
                }
                if (null != value)
                {
                    DataCache[dataCode] = value;
                    total -= len + 1;
                    idx += len;
                }
            } while (total >= 2);
        }

        #region 重写的抽象方法

        /// <summary>
        /// 协议头
        /// </summary>
        public override byte[]? Header { get; protected set; }

        /// <summary>
        /// 表示一帧完整数据至少有多少固定长度
        /// </summary>
        public override int FixLength { get; protected set; } = 11;

        /// <summary>
        /// 数据长度
        /// </summary>
        public override int DataLen { get; protected set; }

        /// <summary>
        /// 检验和
        /// </summary>
        public override int CS { get; protected set; }

        /// <summary>
        /// 将数据帧解析成对应的协议对象
        /// </summary>
        /// <param name="frame">数据帧</param>
        /// <returns></returns>
        public override ProtocolBase? Analysis(byte[] frame, int start, int count)
        {
            if (!StartWith(frame, start, count) || count < FixLength)
                return default;
            int idx = start + HeaderFrame.Length;
            int dataLen = frame[idx + 1] << 8 | frame[idx];
            idx += 2;
            string version = frame.ToIntString(idx, 4, ".");
            idx += 4;
            FrameMode frameMode = (FrameMode)frame[idx++];
            DeviceProtocol? protocol;
            switch (frameMode)
            {
                case FrameMode.HeartBeat:
                    protocol = new DeviceProtocol { FrameMode = frameMode, DataLen = dataLen, Version = version };
                    break;
                case FrameMode.Message:
                    protocol = new DeviceProtocol { FrameMode = frameMode, DataLen = dataLen, Version = version };
                    break;
                default: return default;
            }
            if (null != protocol)
                AnalysisData(frame, idx, dataLen);

            idx += dataLen;
            CS = frame[idx + 1] << 8 | frame[idx];

            Version = protocol?.Version;

            return protocol;
        }

        /// <summary>
        /// 构建数据帧
        /// </summary>
        /// <returns></returns>
        public override byte[]? Build() => default;

        #endregion
    }
}
